package com.wuad.platformwuad.module.study.activiti7Demo.activitiForHoliday;

import org.activiti.engine.*;
import org.activiti.engine.history.HistoricTaskInstance;
import org.activiti.engine.impl.identity.Authentication;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.junit.Test;

import java.io.InputStream;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.zip.ZipInputStream;

/**
 * 简单的请假流程：重点实现流程回退及会签功能
 *
 * @author wuad
 */
public class LeaveTest {
    public static final String PROCESS_DEFINITION_KEY = "holiday";

    /**
     * 第一步：这是创建activiti7所需的表：已经在别的地方建好了，这里就不在执行了
     */
    @Test
    public void createActivitiTable() {
        ProcessEngineConfiguration processEngineConfiguration = ProcessEngineConfiguration.createStandaloneProcessEngineConfiguration();
        processEngineConfiguration.setJdbcDriver("com.mysql.cj.jdbc.Driver");
        processEngineConfiguration.setJdbcUrl("jdbc:mysql://localhost:3306/platform_wad?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai&nullCatalogMeansCurrent=true");
        processEngineConfiguration.setJdbcUsername("root");
        processEngineConfiguration.setJdbcPassword("root");

        //DB_SCHEMA_UPDATE_TRUE 如果表不存在 自动创建表
        processEngineConfiguration.setDatabaseSchemaUpdate(ProcessEngineConfiguration.DB_SCHEMA_UPDATE_TRUE);
        //工作流核心对象 processEngine
        ProcessEngine processEngine = processEngineConfiguration.buildProcessEngine();
        System.out.println("processEngine:"+processEngine);
    }

    /**
     * 第二步：流程部署。根据画好的流程文件，bpmn文件和png文件存入数据库中
     * 这里的bpmn文件使用Eclipse画的
     */
    @Test
    public void devlopModle() {
        // 创建ProcessEngineConfiguration对象
        ProcessEngineConfiguration configuration = ProcessEngineConfiguration.createProcessEngineConfigurationFromResource("activiti-cfg.xml");
        ProcessEngine processEngine = configuration.buildProcessEngine();
        //获取RepositoryService对象
        RepositoryService repositoryService = processEngine.getRepositoryService();
        InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream("process/holiday.zip");
        ZipInputStream zipInputStream = new ZipInputStream(inputStream);
        //进行部署
        Deployment deployment = repositoryService
                .createDeployment()
                .addZipInputStream(zipInputStream)
                .name("请假申请流程")
                // 部署
                .deploy();
        //输出部署的一些信息
        System.out.println("流程部署id = " + deployment.getId());
        System.out.println("流程部署名称 = " + deployment.getName());
    }

    /**
     * 第三步：根据已部署的流程，创建流程实例
     *
     * act_hi_actinst 活动实例
     * act_hi_identitylink 参与者信息
     * act_hi_procinst 流程实例
     * act_hi_taskinst 任务实例
     * act_ru_execution 执行表
     * act_ru_identitylink 参与者信息
     * act_ru_task   任务表
     */
    @Test
    public void beginTest() {
        String businessKey = "新的业务关联用id哎哎哎啊啊";
        String assignee = "我是组长";
        //创建ProcessEngineConfiguration对象
        ProcessEngineConfiguration configuration = ProcessEngineConfiguration.createProcessEngineConfigurationFromResource("activiti-cfg.xml");
        ProcessEngine processEngine = configuration.buildProcessEngine();
        //获取RuntimeService对象
        RuntimeService runtimeService = processEngine.getRuntimeService();
        // 设置流程执行人
        Map<String, Object> variables = new HashMap<>();
        variables.put("assignee", assignee);
        //根据流程定义的key启动流程实例（这个id是MyProcess.xml里面的id）
//        ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(PROCESS_DEFINITION_KEY,variables);
        ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(PROCESS_DEFINITION_KEY,businessKey,variables);
        //获取流程实例的相关信息
        System.out.println("流程定义的id = " + processInstance.getProcessDefinitionId());
        System.out.println("这是个啥：" + processInstance.getProcessDefinitionKey());
        System.out.println("流程部署的id = " + processInstance.getDeploymentId());
        System.out.println("流程实例的id = " + processInstance.getId());
        System.out.println("当前活动的id = " + processInstance.getActivityId());
        System.out.println("业务关联用id = " + processInstance.getBusinessKey());
    }


    /**
     * （4）查询流程
     * 流程启动后，各个任务的负责人就可以查询自己当前需要处理的任务，查询出来的任务都是该用户的待办任务
     */
    @Test
    public void selectTest() {
        //任务负责人
        String assignee = "lisi";
        //创建ProcessEngineConfiguration对象
        ProcessEngineConfiguration configuration = ProcessEngineConfiguration.createProcessEngineConfigurationFromResource("activiti-cfg.xml");
        ProcessEngine processEngine = configuration.buildProcessEngine();
        //获取TaskService对象
        TaskService taskService = processEngine.getTaskService();
        //查询任务列表，根据流程定义的key和任务负责人
        List<Task> taskList = taskService
                .createTaskQuery()
                .processDefinitionKey(PROCESS_DEFINITION_KEY)
//                .processInstanceId("17501")
                .taskAssignee(assignee)
                .list();
        System.out.println("任务列表：" + taskList);
        //遍历任务列表
        for (Task task : taskList) {
            System.out.println("流程定义id = " + task.getProcessDefinitionId());
            System.out.println("流程实例id = " + task.getProcessInstanceId());
            System.out.println("任务负责人 = " + task.getAssignee());
            System.out.println("任务id = " + task.getId());
            System.out.println("任务名称 = " + task.getName());
        }
    }

    /**
     * （5）处理流程：组长审批通过--->部门经理审批
     * 任务负责人查询待办任务，选择任务进行处理，完成任务, 并可指定下个节点审批人。
     */
    @Test
    public void disposeTest() {
        //当前任务负责人
        String assigneeNow = "我是组长";
        // 下一个节点负责人
        String assigneeNext = "我是经理";
        // 业务关联id
        String businessKey = "新的业务关联用id哎哎哎啊啊";
        //创建ProcessEngineConfiguration对象
        ProcessEngineConfiguration configuration = ProcessEngineConfiguration.createProcessEngineConfigurationFromResource("activiti-cfg.xml");
        ProcessEngine processEngine = configuration.buildProcessEngine();
        //获取TaskService对象
        TaskService taskService = processEngine.getTaskService();
        //查询任务列表，根据流程定义的key和任务负责人
//        List<Task> taskList = taskService.createTaskQuery().processDefinitionKey("myProcess").taskAssignee(assignee).list();
        List<Task> taskList = taskService.createTaskQuery().processInstanceBusinessKey(businessKey).list();
        System.out.println("这是个啥：" + taskList);
        // 设置流程执行人
        Map<String, Object> variables = new HashMap<>();
        variables.put("assignee", assigneeNext);
        //遍历任务列表
        for (Task task : taskList) {
            String id = task.getId();
            // 添加审批意见
            //需要添加此句否则审批意见表中ACT_HI_COMMENT，审批人的userId是空的
            Authentication.setAuthenticatedUserId(assigneeNow);
            taskService.addComment(id, task.getProcessInstanceId(),"这是组长填的审批意见");
            //完成任务
//            taskService.complete(id);
            taskService.complete(id, variables);
        }
    }

    /**
     * （6）处理流程：部门经理审批通过--->人事会签审批
     * 任务负责人查询待办任务，选择任务进行处理，完成任务, 并可指定下个节点审批人。
     */
    @Test
    public void disposeTestTwo() {
        //当前任务负责人
        String assigneeNow = "我是经理";
        // 业务关联id
        String businessKey = "新的业务关联用id哎哎哎啊啊";
        //创建ProcessEngineConfiguration对象
        ProcessEngineConfiguration configuration = ProcessEngineConfiguration.createProcessEngineConfigurationFromResource("activiti-cfg.xml");
        ProcessEngine processEngine = configuration.buildProcessEngine();
        //获取TaskService对象
        TaskService taskService = processEngine.getTaskService();
        //查询任务列表，根据流程定义的key和任务负责人
//        List<Task> taskList = taskService.createTaskQuery().processDefinitionKey("myProcess").taskAssignee(assignee).list();
        List<Task> taskList = taskService.createTaskQuery().processInstanceBusinessKey(businessKey).list();
        System.out.println("这是个啥：" + taskList);
        // 设置流程执行人        // 设置下一个节点负责人
        Map<String, Object> variables = new HashMap<>();
        variables.put("approverList", Arrays.asList("lisi","wangwu","zhaoliu"));
        //遍历任务列表
        for (Task task : taskList) {
            String id = task.getId();
            // 添加审批意见
            //需要添加此句否则审批意见表中ACT_HI_COMMENT，审批人的userId是空的
            Authentication.setAuthenticatedUserId(assigneeNow);
            taskService.addComment(id, task.getProcessInstanceId(),"这是部门经理填的审批意见");
            //完成任务
//            taskService.complete(id);
            taskService.complete(id, variables);
        }
    }

    /**
     * （5）处理流程：部门经理审批通过--->人事部门成员之一（会签）审批
     * 下面的方法每次更换会签的人，直到会签所有的人都通过才会进入下一节点
     */
    @Test
    public void disposeTestThree() {
        //当前任务负责人
//        String assigneeNow = "lisi";
//        String assigneeNow = "wangwu";
        String assigneeNow = "zhaoliu";
        // 业务关联id
        String businessKey = "新的业务关联用id哎哎哎啊啊";
        //创建ProcessEngineConfiguration对象
        ProcessEngineConfiguration configuration = ProcessEngineConfiguration.createProcessEngineConfigurationFromResource("activiti-cfg.xml");
        ProcessEngine processEngine = configuration.buildProcessEngine();
        //获取TaskService对象
        TaskService taskService = processEngine.getTaskService();
        //查询任务列表，根据流程定义的key和任务负责人
//        Task task = taskService.createTaskQuery().processInstanceId("107501").taskAssignee(assigneeNow).singleResult();
        List<Task> taskList = taskService.createTaskQuery().processInstanceBusinessKey(businessKey).taskAssignee(assigneeNow).list();
        System.out.println("11111:" + taskList);
        //遍历任务列表
        for (Task task : taskList) {
            String id = task.getId();
            // 添加审批意见
            //需要添加此句否则审批意见表中ACT_HI_COMMENT，审批人的userId是空的
            Authentication.setAuthenticatedUserId(assigneeNow);
            taskService.addComment(id, task.getProcessInstanceId(),"这是" + assigneeNow + "填的审批意见");
            //完成任务
            taskService.complete(id);
        }
    }

    // todo 在会签后面在加上一个任务节点试试

    // todo 试试节点退回

    /**
     * 获取流程历史信息
     */
    @Test
    public void getHistory() {
        // 业务关联id
        String businessKey = "新的业务关联用id哎哎哎啊啊";
        //创建ProcessEngineConfiguration对象
        ProcessEngineConfiguration configuration = ProcessEngineConfiguration.createProcessEngineConfigurationFromResource("activiti-cfg.xml");
        ProcessEngine processEngine = configuration.buildProcessEngine();
        // 得到历史服务组件
        HistoryService historyService = processEngine.getHistoryService();
        // 查询已完成的流程
        List<HistoricTaskInstance> hisTaskList = historyService.createHistoricTaskInstanceQuery()
                .processInstanceBusinessKey(businessKey)
                .orderByTaskCreateTime()
                .desc()
                .list();
        for(HistoricTaskInstance historicTaskInstance : hisTaskList) {
            System.out.println("getId:" + historicTaskInstance.getId());
            System.out.println("getProcessInstanceId:" + historicTaskInstance.getProcessInstanceId());
            System.out.println("getTaskDefinitionKey:" + historicTaskInstance.getTaskDefinitionKey());
            System.out.println("getEndTime:" + historicTaskInstance.getEndTime());
            System.out.println("getAssignee:" + historicTaskInstance.getAssignee());
            System.out.println("getBusinessKey:" + historicTaskInstance.getBusinessKey());
        }
        // 根据节点定义id倒叙排序，取第一条即为退回上个节点
    }


}
